package com.gitee.mars.vaccin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gitee.mars.vaccin.entity.SysMenu;
import com.gitee.mars.vaccin.entity.SysRole;
import com.gitee.mars.vaccin.exception.WorkException;
import com.gitee.mars.vaccin.mapper.SysRoleMapper;
import com.gitee.mars.vaccin.request.SysRoleReq;
import com.gitee.mars.vaccin.response.base.BasePageRequest;
import com.gitee.mars.vaccin.response.base.PageInfo;
import com.gitee.mars.vaccin.response.vo.RoleDetailVo;
import com.gitee.mars.vaccin.response.vo.SysRoleListVo;
import com.gitee.mars.vaccin.service.SysMenuService;
import com.gitee.mars.vaccin.service.SysRoleMenuService;
import com.gitee.mars.vaccin.service.SysRoleService;
import com.gitee.mars.vaccin.utils.DateUtils;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;


/**
 * 实现层
 *
 * @Author wq
 * @Date 2020-12-15
 **/
@Service
@AllArgsConstructor
@Transactional(rollbackFor = RuntimeException.class)
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {


    private final SysMenuService sysMenuService;

    private final SysRoleMenuService sysRoleMenuService;

    @Override
    public IPage<SysRole> page(BasePageRequest query) {
        IPage<SysRole> page = new Page<>(query.getPageNumber(), query.getPageSize());
        return baseMapper.findByQuery(page, query);
    }

    @Override
    public void add(SysRoleReq req) {
        //保存角色
        SysRole role = new SysRole();
        role.setRoleName(req.getRoleTitle());
        role.setUpdateTime(new Date());
        role.setCreateTime(new Date());
        save(role);
        //保存角色ID对应的菜单ID
        Integer roleId = role.getId();
        Set<Integer> menuIds = req.getMenuIds();
        //保存角色菜单中间表
        sysRoleMenuService.saveRelation(roleId, menuIds);
    }

    @Override
    public void updateRole(SysRoleReq req) {
        SysRole sysRole = getById(req.getRoleId());
        if (Objects.isNull(sysRole)) {
            throw new WorkException("数据不存在");
        }

        sysRole.setRoleName(req.getRoleTitle());
        sysRole.setUpdateTime(new Date());
        updateById(sysRole);
        //删除角色删除中间表
        sysRoleMenuService.delRelation(req.getRoleId());
        Set<Integer> ids = buildMenuIds(req.getMenuIds());
        sysRoleMenuService.saveRelation(req.getRoleId(), ids);
    }

    @Override
    public RoleDetailVo detail(Integer id) {
        SysRole role = getById(id);
        RoleDetailVo vo = new RoleDetailVo();
        vo.setId(id);
        vo.setRoleTitle(role.getRoleName());
        List<Integer> relation = sysRoleMenuService.findRelation(id);
        List<Integer> ids = buildDetailMenuIds(relation);
        vo.setMenuIds(ids);
        return vo;
    }

    private List<Integer> buildDetailMenuIds(List<Integer> menuIds) {
        List<Integer> ids = new ArrayList<>();
        for (Integer menuId : menuIds) {
            boolean b = sysMenuService.isExistChildren(menuId);
            if (b) {
                continue;
            }
            ids.add(menuId);
        }
        return ids;
    }

    @Override
    public void delete(Integer id) {
        Integer sysId = baseMapper.selectSysUser(id);
        if (sysId != null) {
            throw new WorkException("该角色下有用户,不能删除");
        }
        baseMapper.deleteById(id);
        //删除角色菜单中间表
        sysRoleMenuService.delRelation(id);

    }

    @Override
    public List<SysRoleListVo> getList() {
        return list().stream().map(i -> {
            SysRoleListVo sysRoleListVo = new SysRoleListVo();
            sysRoleListVo.setCreateTime(DateUtils.formatDateTime(i.getCreateTime()));
            sysRoleListVo.setRoleId(i.getId());
            sysRoleListVo.setRoleTitle(i.getRoleName());
            return sysRoleListVo;
        }).collect(Collectors.toList());
    }

    @Override
    public String selectRoleTile(Integer roleId) {
        return baseMapper.selectRoleTitle(roleId);
    }

    @Override
    public PageInfo<SysRoleListVo> rolePage(SysRoleReq req) {
        IPage<SysRole> page = new Page<>(req.getPageNumber(), req.getPageSize());
        LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNoneEmpty(req.getRoleTitle())) {
            wrapper.like(SysRole::getRoleName, req.getRoleTitle());
        }
        List<SysRoleListVo> list = page(page, wrapper).getRecords().stream().map(i -> {
            SysRoleListVo sysRoleListVo = new SysRoleListVo();
            sysRoleListVo.setCreateTime(DateUtils.formatDateTime(i.getCreateTime()));
            sysRoleListVo.setRoleId(i.getId());
            sysRoleListVo.setRoleTitle(i.getRoleName());
            return sysRoleListVo;
        }).collect(Collectors.toList());
        return new PageInfo<>(page.getTotal(), list);
    }

    @Override
    public List<SysRoleListVo> listRole() {
        return list().stream().map(x -> {
            SysRoleListVo vo = new SysRoleListVo();
            vo.setRoleId(x.getId());
            vo.setRoleTitle(x.getRoleName());
            return vo;
        }).collect(Collectors.toList());
    }

    /**
     * 选择了子类的菜单,父级的菜单也默认选上
     *
     * @param menuIds 菜单集合
     * @return 新的ID集合
     */
    private Set<Integer> buildMenuIds(Set<Integer> menuIds) {
        Set<Integer> ids = new HashSet<>();
        for (Integer menuId : menuIds) {
            //查询当前选中菜单
            SysMenu menu = sysMenuService.getById(menuId);
            //如果当前菜单不是第一级菜单 把他父菜单加进去
            if (!menu.getParentId().equals(0)) {
                ids.add(menu.getParentId());
            }
            //把当前菜单加进去
            ids.add(menuId);
        }
        return ids;
    }

}